package com.xinmao.quantitative.trad.strategies.combine;

import com.xinmao.quantitative.trad.strategies.IStrategy;
import org.springframework.stereotype.Component;
import org.ta4j.core.BarSeries;
import org.ta4j.core.BaseStrategy;
import org.ta4j.core.Rule;
import org.ta4j.core.Strategy;
import org.ta4j.core.indicators.EMAIndicator;
import org.ta4j.core.indicators.helpers.*;
import org.ta4j.core.num.DecimalNum;
import org.ta4j.core.num.Num;
import org.ta4j.core.rules.*;

/**
 * CCI Correction Strategy
 *
 * @see <a href=
 *      "https://school.stockcharts.com/doku.php?id=trading_strategies:cvr3_vix_market_timi">
 *      https://school.stockcharts.com/doku.php?id=trading_strategies:cvr3_vix_market_timi</a>
 */
@Component
public class Cvr3VixMarketStrategy implements IStrategy {

    @Override
    public Strategy buildStrategy(BarSeries series) {

        LowPriceIndicator low = new LowPriceIndicator(series);
        OpenPriceIndicator open = new OpenPriceIndicator(series);
        ClosePriceIndicator close = new ClosePriceIndicator(series);
        HighPriceIndicator high = new HighPriceIndicator(series);

        EMAIndicator ema10 = new EMAIndicator(close, 10);
        EMAIndicator ema1 = new EMAIndicator(close, 1);

        //1:日低点高于其 10 天移动平均线
        //2:每日收盘价至少比其 10 天移动平均线高 10%
        //3:收盘价低于开盘价
        Rule entryRule = new OverIndicatorRule(low, ema10)
                .and(new OverIndicatorRule(ema1, TransformIndicator.multiply(ema10,1.1)))
                .and(new UnderIndicatorRule(close, open));
        //1:日高点低于10日移动平均线
        //2:每日收盘价至少比其 10 天移动平均线低 10%
        //3:收盘价高于开盘价
        Rule exitRule = new UnderIndicatorRule(high, ema10)
                .and(new UnderIndicatorRule(ema1, TransformIndicator.multiply(ema10,0.9)))
                .and(new OverIndicatorRule(close, open))
                //止损：当日收盘低于前一天的 10 天移动平均线
                .or(new UnderIndicatorRule(close,new PreviousValueIndicator(ema10,1)));
        return new BaseStrategy(entryRule, exitRule);
    }

    @Override
    public Num getScore() {
        return DecimalNum.valueOf(1);
    }
}
